package commSql

import (
	"database/sql"
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntity"
	//	_ "github.com/mattn/go-sqlite3" //具体使用的时候，请在服务中，某个go文件中import这一句话
	//	_ "github.com/go-sql-driver/mysql" //具体使用的时候，请在服务中，某个go文件中import这一句话
)

type SQLOption struct {
	DriverName string
	DataSource string
}

type SqlClient struct {
	db *sql.DB
}

func (e *SqlClient) ConnectMySQL() error {
	if e.db != nil {
		e.db.Close()
		e.db = nil
	}

	option := buildMySQLOption()

	// 连接数据库
	db, err := sql.Open(option.DriverName, option.DataSource)
	if err != nil {
		return err
	}

	// 检查数据库连接是否成功
	if err := db.Ping(); err != nil {
		db.Close()
		return err
	}

	e.db = db
	return nil
}

func (e *SqlClient) ConnectSQLite(fileName string) error {
	if e.db != nil {
		e.db.Close()
		e.db = nil
	}

	// 定义数据库连接信息
	option := buildSQLite3Option(fileName)

	// 连接数据库
	db, err := sql.Open(option.DriverName, option.DataSource)
	if err != nil {
		return err
	}

	e.db = db
	return nil
}

func (e *SqlClient) readQueryRows(entityType string, rows *sql.Rows) ([]commEntity.IEntity, error) {
	// 获得返回的列信息
	columns, err := rows.Columns()
	if err != nil {
		return nil, err
	}
	if columns == nil {
		return nil, err
	}

	// 构造一个准备用来接收数据的临时行
	scanRow, err := schema.buildRowVar(entityType, columns)
	if err != nil {
		return nil, err
	}

	result := make([]commEntity.IEntity, 0)
	for rows.Next() {
		// 读取一行数据
		err = rows.Scan(scanRow...)
		if err != nil {
			return nil, err
		}

		// 将row转换为entity
		entity, err := schema.buildEntity(entityType, columns, scanRow)
		if err != nil {
			return nil, err
		}

		// 保存数据
		result = append(result, entity)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return result, nil
}

// SQuery 安全查询数据
// 说明：带预处理的方式执行SQL语句，防止注入攻击，或者特殊字符的冲突
func (e *SqlClient) SQuery(entityType string, sql string, args []interface{}) ([]commEntity.IEntity, error) {
	if e.db == nil {
		return nil, errors.New("尚未与数据库建立未连接")
	}

	// 预处理
	stmt, err := e.db.Prepare(sql)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	// 执行查询
	rows, err := stmt.Query(args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	// 读取行数据
	return e.readQueryRows(entityType, rows)
}

// Query 查询数据
// 说明：直接执行SQL语句，不进行预处理
func (e *SqlClient) Query(entityType string, sql string) ([]commEntity.IEntity, error) {
	if e.db == nil {
		return nil, errors.New("尚未与数据库建立未连接")
	}

	// 执行查询
	rows, err := e.db.Query(sql)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	// 读取行数据
	return e.readQueryRows(entityType, rows)
}

func (e *SqlClient) SQueryList(sql string, fields []FieldValue, args []interface{}) ([]map[string]interface{}, error) {
	if e.db == nil {
		return nil, errors.New("尚未与数据库建立未连接")
	}

	// 预处理
	stmt, err := e.db.Prepare(sql)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	// 执行查询
	rows, err := stmt.Query(args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	return e.readMapListRows(rows, fields)
}

func (e *SqlClient) QueryList(sql string, fields []FieldValue) ([]map[string]interface{}, error) {
	if e.db == nil {
		return nil, errors.New("尚未与数据库建立未连接")
	}
	// 获得返回的列信息
	if len(fields) == 0 {
		return nil, errors.New("fields参数缺失")
	}

	// 执行查询
	rows, err := e.db.Query(sql)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	return e.readMapListRows(rows, fields)
}

func (e *SqlClient) readMapListRows(rows *sql.Rows, fields []FieldValue) ([]map[string]interface{}, error) {
	// 构造一个准备用来接收数据的临时行
	scanRow, err := schema.buildRawRowVar(fields)
	if err != nil {
		return nil, err
	}

	result := make([]map[string]interface{}, 0)
	for rows.Next() {
		// 读取一行数据
		err = rows.Scan(scanRow...)
		if err != nil {
			return nil, err
		}

		data, err := schema.buildRawRow(fields, scanRow)
		if err != nil {
			return nil, err
		}

		// 保存数据
		result = append(result, data)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return result, nil
}

func (e *SqlClient) QueryCount(sql string) (int, error) {
	if e.db == nil {
		return 0, errors.New("尚未与数据库建立未连接")
	}

	count := 0

	// 执行查询
	err := e.db.QueryRow(sql).Scan(&count)
	if err != nil {
		return 0, err
	}

	return count, nil
}

func (e *SqlClient) SQueryCount(sql string, args []interface{}) (int, error) {
	if e.db == nil {
		return 0, errors.New("尚未与数据库建立未连接")
	}

	// 预处理
	stmt, err := e.db.Prepare(sql)
	if err != nil {
		return 0, err
	}
	defer stmt.Close()

	// 执行查询
	count := 0
	err = stmt.QueryRow(args...).Scan(&count)
	if err != nil {
		return 0, err
	}

	return count, nil
}

// Exec 执行sql
// 参数：
//
//	sql 准备执行的sql语句
//	values sql语言中的参数表
//
// 说明：如果你构造的values参数为nil，那么你要确保自己的sql不含有文本参数的语句，不会发生注入式攻击
func (e *SqlClient) Exec(sql string, values []interface{}) (int64, error) {
	if e.db == nil {
		return 0, errors.New("尚未与数据库建立未连接")
	}

	if values != nil && len(values) > 0 {
		// 预处理模式：避免注入攻击和SQL语句中携带了冲突字符的问题
		stmt, err := e.db.Prepare(sql)
		if err != nil {
			return 0, err
		}
		defer stmt.Close()

		// 传递参数
		res, err := stmt.Exec(values...)
		if err != nil {
			return 0, err
		}

		// 获得新增数据的ID
		return res.LastInsertId()
	} else {
		// 简单模式：直接执行SQL语句
		res, err := e.db.Exec(sql)
		if err != nil {
			return 0, err
		}

		return res.LastInsertId()
	}
}
